package com.zycfc.zsf.boot.core.zsfvalue;

import org.springframework.core.*;
import java.lang.ref.*;
import java.lang.reflect.*;
import org.slf4j.*;

public class ZsfValueOperator
{
    private static final Logger log;
    private MethodParameter methodParameter;
    private Field field;
    private WeakReference<Object> beanRef;
    private String beanName;
    private String key;
    private String placeholder;
    private Class<?> targetType;
    private Type genericType;
    private boolean isJson;
    private String defaultValue;
    
    public ZsfValueOperator(final String key, final String placeholder, final Object bean, final String beanName, final Field field, final boolean isJson, final String defaultValue) {
        this.beanRef = new WeakReference<Object>(bean);
        this.beanName = beanName;
        this.field = field;
        this.key = key;
        this.placeholder = placeholder;
        this.targetType = field.getType();
        this.isJson = isJson;
        if (isJson) {
            this.genericType = field.getGenericType();
        }
        this.defaultValue = defaultValue;
    }
    
    public ZsfValueOperator(final String key, final String placeholder, final Object bean, final String beanName, final Method method, final boolean isJson) {
        this.beanRef = new WeakReference<Object>(bean);
        this.beanName = beanName;
        this.methodParameter = new MethodParameter(method, 0);
        this.key = key;
        this.placeholder = placeholder;
        final Class<?>[] paramTps = method.getParameterTypes();
        this.targetType = paramTps[0];
        this.isJson = isJson;
        if (isJson) {
            this.genericType = method.getGenericParameterTypes()[0];
        }
    }
    
    public void update(final Object newVal) throws IllegalAccessException, InvocationTargetException {
        final Object val = this.converValue(newVal);
        if (val == null) {
            return;
        }
        if (this.isField()) {
            this.injectField(val);
        }
        else {
            this.injectMethod(val);
        }
    }
    
    private void injectField(final Object newVal) throws IllegalAccessException {
        final Object bean = this.beanRef.get();
        if (bean == null) {
            return;
        }
        final boolean accessible = this.field.isAccessible();
        this.field.setAccessible(true);
        this.field.set(bean, newVal);
        this.field.setAccessible(accessible);
    }
    
    public Object converValue(final Object newVal) {
        if (newVal == null) {
            return null;
        }
        Object result = newVal;
        if (this.targetType == Integer.class) {
            result = Integer.parseInt(String.valueOf(newVal));
        }
        else if (this.targetType == Boolean.class) {
            result = Boolean.valueOf(String.valueOf(newVal));
        }
        else if (this.targetType == Integer.TYPE) {
            result = Integer.parseInt(String.valueOf(newVal));
        }
        else if (this.targetType == Boolean.TYPE) {
            result = Boolean.valueOf(String.valueOf(newVal));
        }
        return result;
    }
    
    private void injectMethod(final Object newVal) throws InvocationTargetException, IllegalAccessException {
        final Object bean = this.beanRef.get();
        if (bean == null) {
            return;
        }
        this.methodParameter.getMethod().invoke(bean, newVal);
    }
    
    public String getBeanName() {
        return this.beanName;
    }
    
    public Class<?> getTargetType() {
        return this.targetType;
    }
    
    public String getPlaceholder() {
        return this.placeholder;
    }
    
    public MethodParameter getMethodParameter() {
        return this.methodParameter;
    }
    
    public boolean isField() {
        return this.field != null;
    }
    
    public Field getField() {
        return this.field;
    }
    
    public Type getGenericType() {
        return this.genericType;
    }
    
    public boolean isJson() {
        return this.isJson;
    }
    
    boolean isTargetBeanValid() {
        return this.beanRef.get() != null;
    }
    
    public String getKey() {
        return this.key;
    }
    
    public String getDefaultValue() {
        return this.defaultValue;
    }
    
    @Override
    public String toString() {
        final Object bean = this.beanRef.get();
        if (bean == null) {
            return "";
        }
        if (this.isField()) {
            return String.format("key: %s, beanName: %s, field: %s.%s", this.key, this.beanName, bean.getClass().getName(), this.field.getName());
        }
        return String.format("key: %s, beanName: %s,defaultValue:%s, method: %s.%s", this.key, this.beanName, this.defaultValue, bean.getClass().getName(), this.methodParameter.getMethod().getName());
    }
    
    static {
        log = LoggerFactory.getLogger((Class)ZsfValueOperator.class);
    }
}
